package service

import (
	"ao/app/dao"
	"ao/app/model"
	"ao/app/request"
	"bufio"
	"encoding/json"
	"github.com/gogf/gf/net/gtcp"
	"github.com/gogf/gf/os/gcache"
	"github.com/gogf/gf/os/glog"
	"github.com/gogf/gf/text/gstr"
	"github.com/gogf/gf/util/gconv"
	"io"
	"time"
	"unicode"
)

var TcpService = tcpService{}

type tcpService struct {
}

var cacheObj = gcache.New()
var clientParam = request.ClientParams{
	Topic:      "msg",
	Tag:        "online",
	TopicGroup: "mq_test",
}

const ONLINE = "online_"

func close(conn *gtcp.Conn) {
	conn.Close()
}
func (s *tcpService) Tcp() {
	go gtcp.NewServer(":9601", func(conn *gtcp.Conn) {

		defer close(conn)
		receiveStr := ""
		for {
			//buf := make([]byte, 1400)
			//_, err := io.ReadFull(conn, buf)
			//if err != nil && err == io.EOF {
			//	break
			//}
			reader := bufio.NewReader(conn)
			for {
				message, err := reader.ReadString('\n')

				if err != nil || err == io.EOF {
					break
				}
				receiveStr += message
				endStr := gstr.SubStr(message, len(message)-15, 7)
				endStr2 := gstr.SubStr(message, len(message)-17, 7)
				if endStr == "ANTENNA" || endStr2 == "ANTENNA" {
					glog.Info("client data: ", receiveStr)
					reportDevice(receiveStr)
					receiveStr = ""
					break
				}

			}

			//receive := gconv.String(message)
			//index := gstr.Pos(receive, "ANTENNA")
			//breakStr := gstr.SubStr(receive, index+7, 6)
			//result := gstr.Split(receive, breakStr)
			//for i := 0; i < len(result); i++ {
			//	glog.Info("client data: ", result[i])
			//	reportDevice(result[i])
			//}

		}

	}).Run()
}

func reportDevice(str string) {
	result := gstr.Split(str, "$")

	deviceReport := request.ReportParams{}
	//deviceReport.IMEI = gstr.Replace(result[0], "\n", "")
	deviceReport.IMEI = gstr.TrimAll(gstr.SubStr(result[0], len(result[0])-15, 15))
	//res := FRedis.HExists("device_info", deviceReport.IMEI)
	//FRedis.Incr(deviceReport.IMEI)
	//num :=gconv.Int(FRedis.Get(deviceReport.IMEI).Val())
	//if num==6 {
	//	FRedis.Set(deviceReport.IMEI,0, 24*time.Hour)
	//}
	if isDigit(deviceReport.IMEI) && len(deviceReport.IMEI) == 15 {
		redisImei, _ := FRedis.Get(ONLINE + deviceReport.IMEI).Result()
		glog.Infof(" redisImei:%v", redisImei)
		if redisImei != deviceReport.IMEI {
			glog.Infof("上线:%v", redisImei)
			Online(&deviceReport) //缓存不存在或者过期第一次代表上线
		}
		for key, value := range result {
			if key > 0 { //忽略key等于0
				report := gstr.Split(value, ",")
				switch report[0] {
				case "GNRMC":
					deviceReport.Speed = report[7]
					deviceReport.PosX = rmc(report, 3)
					deviceReport.PosY = rmc(report, 5)
					deviceReport.GnssTime = dateFormat(report)
					deviceReport.Direction = report[8]
				case "GNGGA":
					deviceReport.PosH = report[9]
					deviceReport.UsedSat = gconv.Int(report[7])
				}
			}
		}
		keepOnline(&deviceReport) //更新位置信息到数据库
		if deviceReport.PosX != "" && deviceReport.PosY != "" {
			Report(&deviceReport) //上报位置
		}
	} else {
		glog.Infof(" imei:%v", deviceReport.IMEI)
	}
}
func (s *tcpService) CheckOnline() {
	c := time.Tick(21 * time.Second)
	updateParams := request.ReportParams{}
	for _ = range c {

		onlineList, err := FRedis.SMembers("online_device").Result()
		if err == nil {
			for _, v := range onlineList {
				imei, _ := FRedis.Get(ONLINE + v).Result()
				if imei != v {
					glog.Info("imei下线: %v  ", v)
					FRedis.SRem("online_device", v)
					//FRedis.Set(v,0,24*time.Hour)
					updateParams.IMEI = v
					DeviceInfo.updateOffline(&updateParams)
					OnlineParam := request.OnOffline{
						OemSn: v,
					}
					Offline(&OnlineParam)
				}
			}
		} else {
			glog.Debugf("imei err: %v  ", err)
		}
	}
}
func keepOnline(deviceReport *request.ReportParams) {
	err := FRedis.Set(ONLINE+deviceReport.IMEI, deviceReport.IMEI, 20*time.Second)
	if err != nil {
		glog.Info("set 上线redis key result:", err)
	}
	//lastTime := time.UnixMilli(gconv.Int64(deviceReport.GnssTime)).Add(13 * time.Hour).Format(time.RFC3339Nano)
	//lastTime = gstr.SubStr(lastTime, 0, len(lastTime)-6) + "+08:00"

	DeviceInfo.updateKeep(deviceReport) //上报记录
}
func Report(deviceReport *request.ReportParams) {
	DeviceInfoModel := dao.DeviceInfo.M
	deviceInfo := new(model.DeviceInfo)
	findErr := DeviceInfoModel.Where("imei", deviceReport.IMEI).Scan(deviceInfo)
	if findErr != nil {
		glog.Info("db err:", findErr)
	}
	reportMq := request.ReportMq{
		PosX:      deviceReport.PosX,
		PosY:      deviceReport.PosY,
		PosZ:      deviceReport.PosH,
		Speed:     deviceReport.Speed,
		GnssTime:  deviceReport.GnssTime,
		UsedSat:   deviceReport.UsedSat,
		Direction: deviceReport.Direction,

		RadioPower:    deviceInfo.RadioPower,
		SolutionState: deviceInfo.SolutionState,
		Soc:           deviceInfo.Soc,
		DiffDelayed:   deviceInfo.DiffDelayed,
		CoordType:     deviceInfo.CoordType,
		Signal:        deviceInfo.Signal,
		GroupId:       deviceInfo.GroupId,
		GroupName:     deviceInfo.GroupName,
		DeviceId:      deviceInfo.DeviceId,
		OemSn:         deviceInfo.OemSn,
		Type:          deviceInfo.Type,
		CommType:      deviceInfo.CommType,
	}
	glog.Infof("GnssTime :%v", reportMq.GnssTime)
	clientParam.Tag = "point"
	bodyJson, _ := json.Marshal(reportMq)
	RocketMmq.productSendSync(&clientParam, bodyJson)
}
func dateFormat(data []string) string {
	year := "20" + gstr.SubStr(data[9], 4, 2)
	month := "-" + gstr.SubStr(data[9], 2, 2)
	day := "-" + gstr.SubStr(data[9], 0, 2)
	hour := " " + gstr.TrimAll(gstr.SubStr(data[1], 0, 2))
	minute := ":" + gstr.TrimAll(gstr.SubStr(data[1], 2, 2)) //
	second := ":" + gstr.TrimAll(gstr.SubStr(data[1], 4, 6))
	date := year + month + day + hour + minute + second
	timeTemplate := "2006-01-02 15:04:05"
	stamp, err := time.ParseInLocation(timeTemplate, date, time.Local)
	if err != nil {
		stamp = time.Now()
	}
	stamp = stamp.Add(-13 * time.Hour)
	glog.Infof("datetime:%v,str:%v", gconv.String(stamp.UnixMilli()), date)
	return gconv.String(stamp.UnixMilli())
}
func Online(deviceReport *request.ReportParams) {
	FRedis.SAdd("online_device", deviceReport.IMEI)
	OnlineParam := request.OnOffline{
		OemSn: deviceReport.IMEI,
	}
	bodyJson, _ := json.Marshal(OnlineParam)
	RocketMmq.productSendSync(&clientParam, bodyJson)
}
func Offline(body *request.OnOffline) {
	clientParam.Tag = "offline"
	bodyJson, _ := json.Marshal(body)
	RocketMmq.productSendSync(&clientParam, bodyJson)
}

func PosStr(haystack string) string {
	var (
		needle  = `.`
		index   = gstr.Pos(haystack, needle)
		subStr  = gstr.SubStr(haystack, 0, index-2)
		subStr2 = gstr.SubStr(haystack, index-2)
		//subStr3 = gstr.SubStr(haystack, index+1)
	)
	strPos := gconv.String(gconv.Floats(subStr2)[0] / 60)
	str := subStr + gstr.SubStr(strPos, 1, 10)
	return str

}
func rmc(data []string, index int) string {
	if data[2] != "V" {
		return PosStr(data[index])
	} else {
		return ""
	}

}

func isDigit(str string) bool {
	for _, x := range []rune(str) {
		if !unicode.IsDigit(x) {
			return false
		}
	}
	return true
}
